﻿Imports System.Net
Imports System.Net.Mail
Imports System.Text
Imports System.Data

Public Module SMTP

    Public Function CreateEmail(ByVal SendFrom As String,
                                ByVal SendTo As String,
                                ByVal Subject As String,
                                ByVal Body As String,
                                Server As SmtpServer) As Boolean

        Dim mail As New MailMessage

        Try
            With mail
                .From = New MailAddress(SendFrom)
                .To.Add(New MailAddress(SendTo))
                .Subject = Subject

                If Body.ToLower.Contains("<html>") Then
                    .IsBodyHtml = True
                End If

                .Body = Body
            End With

            Dim smtp As New SmtpClient(Server.SmtpServer, Server.SmtpPort)
            smtp.Credentials = New NetworkCredential(Server.SmtpUserId, Server.SmtpPassword)
            smtp.Send(mail)

            Return True

        Catch ex As Exception
            Throw New InvalidOperationException("Failed to create Email.", ex)
        End Try

        Return False
    End Function

    Public Function CreateEmail(ByVal SendFrom As String,
                                ByVal SendTo As String,
                                ByVal Subject As String,
                                ByVal Body As IEnumerable,
                                Server As SmtpServer) As Boolean

        Dim mail As New MailMessage
        Dim sbody As String

        ' opening an html tag and creating a table 
        sbody = "<html><body style=""font-family: Arial, Helvetica, sans-serif;"" ><table border=""1"">"

        Try
            With mail
                .From = New MailAddress(SendFrom)
                .To.Add(New MailAddress(SendTo))
                .Subject = Subject

                If sbody.ToLower.Contains("<html>") Then
                    .IsBodyHtml = True

                    ' object row count
                    Dim iRowCount As Integer
                    ' to extrac attributes using reflection  
                    Dim properties As Reflection.PropertyInfo

                    For Each rowValue In Body
                        ' extracting the header value [once] 
                        If iRowCount = 0 Then
                            ' creating new row for the header
                            sbody = sbody + "<tr>"
                            For Each properties In rowValue.GetType.GetProperties()
                                ' omiting the Detail and the Id reserved words from the header
                                If properties.Name <> "Details" And properties.Name <> "Id" Then
                                    ' creating new cell
                                    sbody = sbody + "<td>"
                                    sbody = sbody + " " + properties.Name
                                    sbody = sbody + "</td>"
                                End If
                            Next
                            ' row ends
                            sbody = sbody + "</tr>"
                        End If

                        ' creating a new row for the attribute values
                        sbody = sbody + "<tr>"
                        ' extracting table attribute values 
                        For Each properties In rowValue.GetType.GetProperties()
                            ' omiting the ID & Details reserved words for attribute values
                            If properties.Name <> "Id" And properties.Name <> "Details" Then
                                ' creating new table cell
                                sbody = sbody + "<td>"
                                sbody = sbody & " " & properties.GetValue(Body(iRowCount), Nothing).ToString()
                                sbody = sbody + "</td>"
                            End If
                        Next
                        ' row ends
                        sbody = sbody + "</tr>"
                        iRowCount += 1
                    Next

                    ' closing the tags
                    sbody = sbody + "</table></body></html>"
                End If

                .Body = sbody
            End With

            Dim smtp As New SmtpClient(Server.SmtpServer, Server.SmtpPort)
            smtp.Credentials = New NetworkCredential(Server.SmtpUserId, Server.SmtpPassword)
            smtp.Send(mail)

            Return True

        Catch ex As Exception
            Throw New InvalidOperationException("Failed to create Email.", ex)
        End Try

        Return False
    End Function

    Public Function CreateAppointment(ByVal SendFrom As String,
                                      ByVal SendTo As String,
                                      ByVal Subject As String,
                                      ByVal Body As String,
                                      ByVal Location As String,
                                      ByVal StartTime As Date,
                                      ByVal EndTime As Date,
                                      ByVal MsgID As String,
                                      ByVal Sequence As Integer,
                                      ByVal IsCancelled As Boolean,
                                      Server As SmtpServer) As Boolean


        Dim result = False
        Try
            If SendTo = "" OrElse SendFrom = "" Then
                Throw New InvalidOperationException("SendFrom and SendTo email addresses must be specified.")
            End If

            Dim fromAddress = New MailAddress(SendFrom)
            Dim toAddress = New MailAddress(SendTo)
            Dim mail As New MailMessage

            With mail
                .Subject = Subject
                .From = fromAddress

                'Need to send to both parties to organize the meeting
                .To.Add(toAddress)
                .To.Add(fromAddress)
            End With

            'Use the text/calendar content type 
            Dim ct As New System.Net.Mime.ContentType("text/calendar")
            ct.Parameters.Add("method", "REQUEST")
            'Create the iCalendar format and add it to the mail
            Dim cal = CreateICal(SendFrom, SendTo, Subject, Body, Location,
                                 StartTime, EndTime, MsgID, Sequence, IsCancelled)
            mail.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(cal, ct))

            'Send the meeting request
            Dim smtp As New SmtpClient(Server.SmtpServer, Server.SmtpPort)
            smtp.Credentials = New NetworkCredential(Server.SmtpUserId, Server.SmtpPassword)
            smtp.Send(mail)

            result = True

        Catch ex As Exception
            Throw New InvalidOperationException("Failed to send Appointment.", ex)
        End Try

        Return result

    End Function

    Private Function CreateICal(ByVal SendFrom As String,
                               ByVal SendTo As String,
                               ByVal Subject As String,
                               ByVal Body As String,
                               ByVal Location As String,
                               ByVal StartTime As Date,
                               ByVal EndTime As Date,
                               ByVal MsgID As String,
                               ByVal Sequence As Integer,
                               ByVal IsCancelled As Boolean) As String

        Dim sb As New StringBuilder()
        If MsgID = "" Then
            MsgID = Guid.NewGuid().ToString()
        End If

        'See iCalendar spec here: http://tools.ietf.org/html/rfc2445
        'Abridged version here: http://www.kanzaki.com/docs/ical/
        sb.AppendLine("BEGIN:VCALENDAR")
        sb.AppendLine("PRODID:-//Microsoft LightSwitch")
        sb.AppendLine("VERSION:2.0")
        If IsCancelled Then
            sb.AppendLine("METHOD:CANCEL")
        Else
            sb.AppendLine("METHOD:REQUEST")
        End If
        sb.AppendLine("BEGIN:VEVENT")
        If IsCancelled Then
            sb.AppendLine("STATUS:CANCELLED")
            sb.AppendLine("PRIORITY:1")
        End If
        sb.AppendLine(String.Format("ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT:MAILTO:{0}", SendTo))
        sb.AppendLine(String.Format("ORGANIZER:MAILTO:{0}", SendFrom))
        sb.AppendLine(String.Format("DTSTART:{0:yyyyMMddTHHmmssZ}", StartTime.ToUniversalTime))
        sb.AppendLine(String.Format("DTEND:{0:yyyyMMddTHHmmssZ}", EndTime.ToUniversalTime))
        sb.AppendLine(String.Format("LOCATION:{0}", Location))
        sb.AppendLine("TRANSP:OPAQUE")
        'You need to increment the sequence anytime you update the meeting request. 
        sb.AppendLine(String.Format("SEQUENCE:{0}", Sequence))
        'This needs to be a unique ID. A GUID is created when the appointment entity is inserted
        sb.AppendLine(String.Format("UID:{0}", MsgID))
        sb.AppendLine(String.Format("DTSTAMP:{0:yyyyMMddTHHmmssZ}", DateTime.UtcNow))
        sb.AppendLine(String.Format("DESCRIPTION:{0}", Body))
        sb.AppendLine(String.Format("SUMMARY:{0}", Subject))
        sb.AppendLine("CLASS:PUBLIC")
        'Create a 15min reminder
        sb.AppendLine("BEGIN:VALARM")
        sb.AppendLine("TRIGGER:-PT15M")
        sb.AppendLine("ACTION:DISPLAY")
        sb.AppendLine("DESCRIPTION:Reminder")
        sb.AppendLine("END:VALARM")

        sb.AppendLine("END:VEVENT")
        sb.AppendLine("END:VCALENDAR")

        Return sb.ToString()
    End Function



End Module